import datetime
import json
import requests
import pandas as pd

from tools.wrappers import deco_retry

api_key = 'b952a5c5-dbd9-4671-8a69-bb5949aa8190'

@deco_retry(retry=5, retry_sleep=15)
def get_all_coins_info(status='inactive,active,untracked'):
    header = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36'}

    df_list = []
    start = 1
    page_size = 5000
    while start < 100000:
        print(f'开始进行获取第{start//5000+1}页数据')
        url = f'https://api.coinmarketcap.com/data-api/v3/map/all?listing_status={status}&' \
              f'exchangeAux=is_active,status&' \
              f'cryptoAux=is_active,status,platform,first_historical_data,last_historical_data&' \
              f'start={start}&limit={page_size}'
        res = requests.get(url, headers=header, timeout=30)
        res = json.loads(res.text)
        df = pd.DataFrame(res['data']['cryptoCurrencyMap'])

        df_list.append(df)
        if df.shape[0] < page_size:  # 数据已经全部获取，无需再获取
            break
        else:
            start = start + page_size
    coins_info = pd.concat(df_list, axis=0, ignore_index=True)
    return coins_info


@deco_retry(retry=5, retry_sleep=15)
def get_all_tags_info():
    header = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36'}
    url = f'https://api.coinmarketcap.com/data-api/v3/cryptocurrency/listing?start=1&limit=20000&sortBy=market_cap&sortType=desc&convert=USD&' \
          f'cryptoType=all&tagType=all&audited=false&' \
          f'aux=tags'
    res = requests.get(url, headers=header, timeout=30)
    res = json.loads(res.text)
    tags_info = pd.DataFrame(res['data']['cryptoCurrencyList'])
    return tags_info


@deco_retry(retry=500, retry_sleep=30)
def get_daily_ohlcvm_by_id_via_http(id=None, **kwargs):
    print(f'开始获取id={id}的所有OHLCVM数据')
    range = kwargs.pop('range', 'ALL')

    header = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36'}
    url = f'https://api.coinmarketcap.com/data-api/v3/cryptocurrency/detail/chart?id={id}&range={range}'
    a = requests.get(url, headers=header, timeout=5)
    res = json.loads(a.text)
    if 'data' not in res.keys():
        print(f'id={id}的数据无法获取, 提示{res["status"]}')
        return pd.DataFrame()
    elif a.status_code == 200 and len(res['data']) == 0:
        print(f'id={id}的数据为空无法获取')
        return pd.DataFrame()
    res_list = []
    for item in res['data']['points']:
        res_list.append([item] + res['data']['points'][item]['v'])
    df = pd.DataFrame(res_list, columns=['time_stamp', 'close', 'amount', 'market_cap', 'price_in_btc', 'circulating_supply'])
    df['circulating_supply'] = df['circulating_supply'] / df['price_in_btc']
    df['volume'] = df['amount'] / (df['close'])
    df['end_date'] = pd.to_datetime(df['time_stamp'], unit='s').dt.tz_localize('UTC').dt.tz_convert('+0000')
    df['end_date'] = df['end_date'].dt.strftime('%Y-%m-%d')
    df['datetime'] = pd.to_datetime(df['time_stamp'], unit='s').dt.tz_localize('UTC').dt.tz_convert('+0000')
    df['datetime'] = df['datetime'].dt.strftime('%Y-%m-%d %H:%M:%S')
    df.sort_values(by=['datetime'], inplace=True)

    df = df.groupby('end_date')[['time_stamp', 'close', 'market_cap', 'price_in_btc', 'circulating_supply', 'datetime','amount', 'volume']].last()
    today = datetime.datetime.now().strftime('%Y-%m-%d')
    df = df[df.index != today]
    print(f'id={id}的所有OHLCVM数据获取成功')
    return df


@deco_retry(retry=50, retry_sleep=15)
def get_total_marketcap_and_amount_via_http(exclude_btc=False, start_date='2013-04-28',**kwargs):
    today = datetime.datetime.now()
    start_date = datetime.datetime.strptime(start_date, '%Y-%m-%d')
    start_timestamp = int(datetime.datetime.timestamp(start_date))
    end_timestamp = int(datetime.datetime.timestamp(today))

    date_pair_list = []
    while (today - start_date).days > 1200:
        date_pair_list.append([int(datetime.datetime.timestamp(start_date + datetime.timedelta(days=1200))),start_timestamp])
        start_date = start_date + datetime.timedelta(days=1195)
        start_timestamp = int(datetime.datetime.timestamp(start_date))
    date_pair_list.append([end_timestamp, start_timestamp])

    header = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36'}

    df_list = []
    for date_pair in date_pair_list:
        if exclude_btc:
            url = f'https://api.coinmarketcap.com/data-api/v3/global-metrics/quotes/historical?format=chart_altcoin&interval=1d&timeEnd={date_pair[0]}&timeStart={date_pair[1]}'
        else:
            url = f'https://api.coinmarketcap.com/data-api/v3/global-metrics/quotes/historical?format=chart&interval=1d&timeEnd={date_pair[0]}&timeStart={date_pair[1]}'
        a = requests.get(url, headers=header, timeout=30)
        res = json.loads(a.text)
        if 'data' not in res.keys():
            print(f'数据无法获取, 提示{res["status"]["error_message"]}')
            return None
        elif a.status_code == 200 and len(res['data']) == 0:
            print(f'数据为空无法获取')
            return None
        res_list = []
        for item in res['data']['quotes']:
            item_quote = item.pop('quote')
            item.update(item_quote[0])
            res_list.append(item)
        df = pd.DataFrame(res_list)

        if not df.empty:
            df = df[['timestamp', 'totalMarketCap', 'totalVolume24H', 'totalVolume24HReported', 'btcDominance']]
            df.rename(columns={'totalMarketCap': 'market_cap', 'totalVolume24H': 'amount', 'totalVolume24HReported': 'amount_reported'}, inplace=True)
            df['timestamp'] = pd.to_datetime(df['timestamp'])
            df['timestamp'] = df['timestamp'].apply(lambda x: x - datetime.timedelta(seconds=1))  # 时间记录的为0点，但是其实是统计的前一天的数据； 统一减去1秒，调整到昨天
            df['end_date'] = df['timestamp'].dt.strftime('%Y-%m-%d')
            df['datetime'] = df['timestamp'].dt.strftime('%Y-%m-%d %H:%M:%S')
            df.drop(['timestamp'], axis=1, inplace=True)
            df.set_index('end_date', inplace=True)
            df.sort_values(by=['end_date'], inplace=True)
            df_list.append(df)

    all_df = pd.concat(df_list, axis=0)
    if '2022-05-12' not in all_df.index:  #
        all_df.loc['2022-05-12', 'market_cap'] = 1225934966070.32
        all_df.loc['2022-05-12', 'amount'] = 197051431678.51
        all_df.loc['2022-05-12', 'amount_reported'] = 500887098639.66
        all_df.loc['2022-05-12', 'btcDominance'] = 44.46
        all_df.loc['2022-05-12', 'datetime'] = '2022-05-12 23:59:59'
    if '2023-01-04' not in all_df.index:  #
        all_df.loc['2023-01-04', 'market_cap'] = 820040249248.98
        all_df.loc['2023-01-04', 'amount'] = 32579218979.2
        all_df.loc['2023-01-04', 'amount_reported'] = 126276002454.92
        all_df.loc['2023-01-04', 'btcDominance'] = 39.5279
        all_df.loc['2023-01-04', 'datetime'] = '2023-01-04 23:59:59'
    # 2021-02-26， 2022-02-23数据异常，需要手动修改
    all_df.loc['2021-02-26', 'amount'] = 154578653169.09
    all_df.loc['2021-02-26', 'amount_reported'] = 399981671502.26
    all_df.loc['2022-02-23', 'amount'] = 82904025618.43

    all_df.sort_index(inplace=True)
    all_df = all_df[~all_df.index.duplicated(keep='first')]  # 去重
    all_df = all_df[all_df.index != today]  # 今天的数据不完整，剔除掉
    print(f'coinmarketcap网站上的所有币的市值，与总的交易金额获取成功')

    return all_df

if __name__ == '__main__':
    get_total_marketcap_and_amount_via_http()
